package com.zmn.oms.third.youzan.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.zmn.base.common.data.common.dro.area.AreaDRO;
import com.zmn.base.common.data.dubbo.interfaces.area.AreaListRemoteService;
import com.zmn.common.constant.GlobalConsts;
import com.zmn.common.dictionary.GlobalDict;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.common.utils.math.MoneyUtil;
import com.zmn.common.utils.string.StringUtil;
import com.zmn.manager.redis.RedisManager;
import com.zmn.oms.business.interfaces.baidumap.BaiduMapBService;
import com.zmn.oms.common.constant.OrderConsts;
import com.zmn.oms.common.constant.RedisKeyConsts;
import com.zmn.oms.model.bo.order.OrderBO;
import com.zmn.oms.model.dto.baidumap.LngLatLocation;
import com.zmn.oms.model.dto.order.proxy.CreateOrderDTO;
import com.zmn.oms.model.dto.product.OrderProductDTO;
import com.zmn.oms.model.entity.work.OrderWork;
import com.zmn.oms.model.vo.work.ZsOrderWorkVO;
import com.zmn.oms.services.interfaces.order.OrderChangeService;
import com.zmn.oms.third.base.dto.api.ApiInvokResult;
import com.zmn.oms.third.toutiao.HeadlinesConsts;
import com.zmn.oms.third.youzan.YouzanApiInvoker;
import com.zmn.oms.third.youzan.YouzanConsts;
import com.zmn.oms.third.youzan.api.OrderClue;
import com.zmn.oms.third.youzan.api.TokenData;
import com.zmn.oms.third.youzan.service.YouzanService;
import com.zmn.oms.zmn.business.interfaces.proxy.ProxyOrderBService;
import com.zmn.oms.zmn.business.interfaces.work.ZsOrderWorkQueryBService;
import com.zmn.oms.zmn.business.interfaces.work.autoflow.WorkFlowContextBService;
import com.zmn.pay.common.constant.PayConsts;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.LinkedList;
import java.util.List;
import java.util.Optional;


/**
 * @author huangyifeng
 * @Description
 * @date 2020/4/27 17:11
 */
/**
 *  有赞渠道从CDS重新接入 2022-01-12
 */
@Deprecated
@Slf4j
//@Service
public class YouzanServiceImpl implements YouzanService {


    @Reference(version = com.zmn.base.plat.engine.common.constant.DubboConsts.INTERFACE_VERSION , check = false)
    protected AreaListRemoteService areaListRemoteService;

    @Autowired
    protected ZsOrderWorkQueryBService zsOrderWorkQueryBService;
    @Autowired
    private ProxyOrderBService proxyOrderBService;
    @Autowired
    private WorkFlowContextBService workFlowContextBService;
    @Autowired
    private OrderChangeService orderChangeService;
    @Autowired
    private BaiduMapBService baiduMapBService;
    @Autowired
    private RedisManager redisManager;


    @Override
    public void pullOrders()  {
        try {
            ApiInvokResult<OrderClue> orderCluesResult = YouzanApiInvoker.getOrderClues(getToken());
            if (!orderCluesResult.isSuccess()) {
                log.info("【{}】获取订单线索失败：{}，result=[{}]", YouzanConsts.CHANNEL_NAME, orderCluesResult.getMsg(),
                        JSON.toJSONString(orderCluesResult));

                // token 过期错误码：4203
                if ("4203".equals(orderCluesResult.getCode())) {
                    // 丢弃当前缓存的token，下次请求是自动获取新的token
                    discardCacheToken();
                }
                return;
            }

            OrderClue data = orderCluesResult.getData();

            List<CreateOrderDTO> zmnOrders = convert2ZmnCreateOrderDTOList(data);
            saveNewOrder(zmnOrders);

        } catch (Exception e) {
            log.error(String.format("【%s】获取订单线索失败：%s", YouzanConsts.CHANNEL_NAME, e.getMessage()), e);
        }
    }

    /**
     * 将线索转成啄木鸟录单对象
     * @param orderClue
     * @return
     */
    private List<CreateOrderDTO> convert2ZmnCreateOrderDTOList(OrderClue orderClue) {
        List<CreateOrderDTO> zmnOrderList = new LinkedList<>();

        // 保存订单
        List<OrderClue.FullOrderInfoList> fullOrderInfoList = orderClue.getFullOrderInfoList();
        for (OrderClue.FullOrderInfoList item : fullOrderInfoList) {
            OrderClue.FullOrderInfo fullOrderInfo = item.getFullOrderInfo();

            OrderClue.OrderInfo orderInfo = fullOrderInfo.getOrderInfo();
            OrderClue.AddressInfo addressInfo = fullOrderInfo.getAddressInfo();

            Boolean isPayed = orderInfo.getOrderTags().getIsPayed();
            if (isPayed == null || !isPayed) {
                log.info("【{}】未支付订单线索（已忽略）：fullOrderInfo=[{}]", YouzanConsts.CHANNEL_NAME,
                        JSON.toJSONString(fullOrderInfo));
                continue;
            }
            if ( StringUtils.isBlank(addressInfo.getReceiverTel())) {
                log.info("【{}】无电话号码数据（已忽略）fullOrderInfo=[{}]", YouzanConsts.CHANNEL_NAME,
                        JSON.toJSONString(fullOrderInfo));
                continue;
            }

            for (OrderClue.Order youzanOrder : fullOrderInfo.getOrders()) {
                String outerId = youzanOrder.getOid();

                if (StringUtil.isBlank(youzanOrder.getOuterItemId())) {
                    log.info("【{}】不存在产品ID（已忽略） OuterId:[{}]", YouzanConsts.CHANNEL_NAME, outerId);
                    continue;
                }
                ZsOrderWorkVO dbOrderWorkVO = zsOrderWorkQueryBService.findOrderWorkByOuterId(outerId,
                        YouzanConsts.CHANNEL_ID);
                if (dbOrderWorkVO != null) {
                    log.info("【{}】重复的消息数据（已忽略） OuterId:[{}]", YouzanConsts.CHANNEL_NAME, outerId);
                    continue;
                }

                CreateOrderDTO zmnOrder = buildOrderDTO(item, youzanOrder);
                if (zmnOrder != null) {
                    zmnOrderList.add(zmnOrder);
                }
            }
        }

        return zmnOrderList;
    }

    /**
     * 保存新单
     * @param zmnOrders
     * @throws Exception
     */
    private void saveNewOrder(List<CreateOrderDTO> zmnOrders) {
        for (CreateOrderDTO zmnOrder : zmnOrders) {
            try {
                OrderBO orderBO = proxyOrderBService.createOrder(zmnOrder);

                OrderWork orderWork = orderBO.getOrderWork();
                try {
                    // 工单自动流转
                    workFlowContextBService.asyncAutoFlow(orderWork.getOrderId(),orderWork.getWorkId());
                } catch (Exception ex) {
                    log.error(String.format("【%s】订单自动流转失败：%s, orderId=[%s]", YouzanConsts.CHANNEL_NAME,
                            ex.getMessage(), String.valueOf(orderWork.getOrderId())), ex);
                }
            } catch (Exception e) {
                log.error(String.format("【%s】录单失败：%s, CreateOrderDTO=[%s]", YouzanConsts.CHANNEL_NAME,
                        e.getMessage(), JSON.toJSONString(zmnOrder)), e);
            }
        }
    }

    private CreateOrderDTO buildOrderDTO(OrderClue.FullOrderInfoList fullOrderInfoList,  OrderClue.Order youzanOrder) {

        OrderClue.FullOrderInfo fullOrderInfo = fullOrderInfoList.getFullOrderInfo();

        OrderClue.OrderInfo orderInfo = fullOrderInfo.getOrderInfo();
        OrderClue.AddressInfo addressInfo = fullOrderInfo.getAddressInfo();

        CreateOrderDTO createOrderDTO = new CreateOrderDTO();
        createOrderDTO.setChannelId(YouzanConsts.CHANNEL_ID);

        String oid = youzanOrder.getOid();
        String tid = orderInfo.getTid();

        createOrderDTO.setOuterId(oid);
        createOrderDTO.setContactName(addressInfo.getReceiverName());
        createOrderDTO.setTelephone(addressInfo.getReceiverTel());

        // 将同步数据中的订单关键信息记录进日志中
        createOrderDTO.setOperatorLogRemark(String.format("订单编号：%s，子单号：%s；", tid, oid));

        {
            // 生成该订单对应的outerData
            String outerData = null;

            List<OrderClue.Order> youzanOrders = fullOrderInfo.getOrders();
            fullOrderInfo.setOrders(Lists.newArrayList(youzanOrder));
            outerData = JSON.toJSONString(fullOrderInfoList);
            // 将数据恢复原样
            fullOrderInfo.setOrders(youzanOrders);

            createOrderDTO.setOuterData(outerData);
        }

        try {
            // 备注
            String token = getToken();
            ApiInvokResult<OrderClue.FullOrderInfoList>
                    orderDetailResult = YouzanApiInvoker.getOrderDetail(token, orderInfo.getTid());
            if (orderDetailResult.isSuccess()) {
                String remark = null;
                try {
                    remark = orderDetailResult.getData().getFullOrderInfo().getRemarkInfo().getBuyerMessage();
                } catch (NullPointerException npe) {
                }
                createOrderDTO.setRemark(remark);
            }
        } catch (Exception e) {
            log.error(String.format("【%s】获取订单备注信息失败：%s, Tid=[%s]", YouzanConsts.CHANNEL_NAME,
                    e.getMessage(), tid), e);
        }

        try {
            // 地址转换
            fillAddress(createOrderDTO, addressInfo);
            // 商品转换
            fillProductInfo(createOrderDTO, youzanOrder);
        } catch (Exception e) {
            log.error(String.format("[%s] ErrorMsg:[%s]", HeadlinesConsts.HEADLINES, e.getMessage()), e);
            return null;
        }

        createOrderDTO.setPlat(GlobalConsts.PLAT_MARK_ZMN);
        createOrderDTO.setGender(GlobalDict.GENDER_NO);
        createOrderDTO.setDisableDiscard(GlobalConsts.NO);
        createOrderDTO.setOperator("系统");
        createOrderDTO.setOperatorId((long) GlobalConsts.OPERATE_USER_TYPE_SYSTEM);
        createOrderDTO.setOperatorType(GlobalConsts.OPERATE_USER_TYPE_CHANNEL);
        createOrderDTO.setInputType(OrderConsts.ORDER_INPUT_TYPE_API);

        return createOrderDTO;
    }


    /**
     * 补全订单地址：将头条订单地址转换成符合我们自己系统使用的地址信息
     * @param zmnOrder
     * @param addressInfo
     */
    private void fillAddress(CreateOrderDTO zmnOrder, OrderClue.AddressInfo addressInfo) {
        String province = Optional.ofNullable(addressInfo.getDeliveryProvince()).orElse("");
        String city = Optional.ofNullable(addressInfo.getDeliveryCity()).orElse("");
        String district = Optional.ofNullable(addressInfo.getDeliveryDistrict()).orElse("");
        String address = Optional.ofNullable(addressInfo.getDeliveryAddress()).orElse("");

        zmnOrder.setStreet(district + address); // street字段在数据库中不能为空
        zmnOrder.setAddress("");
        // 记录一下完整地址
        StringBuilder logRemark = new StringBuilder();
        logRemark.append(zmnOrder.getOperatorLogRemark())
                .append(province)
                .append(city)
                .append(district)
                .append(address);
        zmnOrder.setOperatorLogRemark(logRemark.toString());

        String lng = null;
        String lat = null;

        // 提取线索中提供的经纬度信息
        // 格式：{\"areaCode\":\"330106\",\"lon\":120.13278695112612,\"lat\":30.2811003548167}
        String addressExtra = addressInfo.getAddressExtra();
        if (StringUtil.isNotBlank(addressExtra)) {
            try {
                JSONObject jsonObj = JSON.parseObject(addressExtra);

                lng = jsonObj.getString("lon");
                lat = jsonObj.getString("lat");
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
        }

        // 如果线索中没有经纬度信息，使用百度地址反解析经纬度信息
        if (StringUtil.isBlank(lng) || StringUtil.isBlank(lat)) {
            String locationAddress = province + city + district + address;
            if (StringUtils.isNotBlank(locationAddress)) {
                LngLatLocation location = baiduMapBService.location(locationAddress.replaceAll(" ", ""));
                if (location != null) {
                    lng = location.getLng();
                    lat = location.getLat();
                }
            }
        }

        if (StringUtil.isNotBlank(lng) && StringUtil.isNotBlank(lat)) {
            try {
                Double lngDbl = Double.valueOf(lng);
                Double latDbl = Double.valueOf(lat);
                ResponseDTO<AreaDRO> areaResponse = areaListRemoteService.getAreaByLatAndLng(lngDbl, latDbl);
                AreaDRO areaDRO = areaResponse.getData();
                if (areaDRO != null) {
                    zmnOrder.setCityId(areaDRO.getParentId());
                    zmnOrder.setLongitude(lngDbl);
                    zmnOrder.setLatitude(latDbl);
                }
            } catch (Exception e) {
                log.error(String.format("【%s】使用经纬度获取CityId失败：%s", YouzanConsts.CHANNEL_NAME,
                        e.getMessage()), e);
            }
        }
    }

    /**
     * 补全产品信息
     * @param zmnOrder
     * @param youzanOrder
     */
    private void fillProductInfo(CreateOrderDTO zmnOrder, OrderClue.Order youzanOrder) {
        OrderProductDTO orderProduct = new OrderProductDTO();

        int productId = OrderConsts.CHANNEL_DISABLED_PRODUCT_ID;
        String outerItemId = youzanOrder.getOuterItemId();
        if (StringUtil.isNotBlank(outerItemId)) {
            productId = Integer.valueOf(outerItemId);
        }
        orderProduct.setProductId(productId);

        Long num = youzanOrder.getNum();
        orderProduct.setNumber((num != null) ? num.intValue() : 1);

        zmnOrder.setOrderProductList(Lists.newArrayList(orderProduct));

        //渠道预付款
        String payment = youzanOrder.getPayment();
        if (StringUtil.isNotBlank(payment)) {
            Integer prepayAmount = MoneyUtil.parseToFen(Double.valueOf(payment));

            if (prepayAmount > 0) {
                zmnOrder.setChannelPrepayAmount(prepayAmount);
                zmnOrder.setChannelPrepayStatus(PayConsts.PAY_STATUS_DONE);
                return;
            }
        }

        zmnOrder.setChannelPrepayStatus(PayConsts.PAY_STATUS_NONE);
    }

    /**
     * 获取token
     * @return
     */
    private String getToken() {
        String token = redisManager.get(RedisKeyConsts.YOUZAN_REDIS_KEY_TOKEN);

        if (StringUtil.isBlank(token)) {
            ApiInvokResult<TokenData> tokenResult = YouzanApiInvoker.getToken(YouzanConsts.SHOP_ID);
            if (!tokenResult.isSuccess()) {
                log.info("【{}】获取Token失败：{}，result=[{}]", YouzanConsts.CHANNEL_NAME, tokenResult.getMsg(),
                        JSON.toJSONString(tokenResult));
                return null;
            }

            TokenData tokenData = tokenResult.getData();
            token = tokenData.getAccessToken();

            // 计算过期时间
            Long expires = tokenData.getExpires();
            long currTime = System.currentTimeMillis();
            int seconds = (int)(expires - currTime);

            redisManager.setex(RedisKeyConsts.YOUZAN_REDIS_KEY_TOKEN, token, seconds - 10);
        }

        return token;
    }

    /**
     * 丢弃当前缓存的token
     */
    private void discardCacheToken() {
        redisManager.del(RedisKeyConsts.YOUZAN_REDIS_KEY_TOKEN);
    }

}
